#include "Hmi/RSFWTooLPin/RSFWTooLPinOpenGLView.h"
#include <QDebug>
#include <QFile>
#include <QStringList>
#include <QtMath>
#include <QOpenGLBuffer>
#include <QOpenGLShaderProgram>
#include <QOpenGLExtraFunctions>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QCoreApplication>
#include <QDir>

RSFSWPinToolOpenGLView::RSFSWPinToolOpenGLView(QWidget *parent) : QOpenGLWidget(parent),
                                  VBO_Base(QOpenGLBuffer::VertexBuffer),
                                  VBO_Tool(QOpenGLBuffer::VertexBuffer),
                                  xtrans(0),
                                  ytrans(0),
                                  ztrans(0){
    this->loaddone = false;
    QSurfaceFormat format;
    format.setAlphaBufferSize(24);
    format.setVersion(3,3);
    format.setSamples(10);
    this->setFormat(format);

    this->PinPos = 0; 

    QString strPath = QCoreApplication::applicationDirPath(); QDir dir(strPath);
    bool bSuccess = dir.cdUp(); bSuccess = dir.cdUp(); strPath = dir.path();

    vertices_Base = loadAscllStl(strPath + "/_APP/RobotModel/RSFWPIN/base.stl",0.001);
    vertices_Tool = loadAscllStl(strPath + "/_APP/RobotModel/RSFWPIN/pin.stl",0.001);

    this->loaddone = true;
    this->looprundelay = 0;
}

RSFSWPinToolOpenGLView::~RSFSWPinToolOpenGLView(){
    this->loaddone = false;
    this->looprundelay = 0;
    makeCurrent();
}

QVector<float> RSFSWPinToolOpenGLView::loadAscllStl(QString filename,float ratio){
    QVector<float> vertices_temp;
    QFile file(filename);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)){
    }
    while (!file.atEnd()){
        QString line = file.readLine().trimmed();
        QStringList  words = line.split(' ', QString::SkipEmptyParts);

        if (words[0] == "facet") {
            Normal = {ratio*words[2].toFloat(), ratio*words[3].toFloat(),ratio*words[4].toFloat()};
        }
        else if (words[0] == "vertex") {
            Position = {ratio*words[1].toFloat(), ratio*words[2].toFloat(),ratio*words[3].toFloat()};
            vertices_temp.append(Position);
            vertices_temp.append(Normal);
        }
        else{
          continue;
        }
    }
    file.close();
    return vertices_temp;
}

void RSFSWPinToolOpenGLView::initializeGL(){
    this->initializeOpenGLFunctions();
    shaderprogram_base.create();
    if(!shaderprogram_base.addShaderFromSourceFile(QOpenGLShader::Vertex,QCoreApplication::applicationDirPath()+ "/stl.vert")){ }
    if(!shaderprogram_base.addShaderFromSourceFile(QOpenGLShader::Fragment,QCoreApplication::applicationDirPath() +"/base.frag")){ }
    if(!shaderprogram_base.link()){ }

    shaderprogram_tool.create();
    if(!shaderprogram_tool.addShaderFromSourceFile(QOpenGLShader::Vertex,QCoreApplication::applicationDirPath()+ "/stl.vert")){ }
    if(!shaderprogram_tool.addShaderFromSourceFile(QOpenGLShader::Fragment,QCoreApplication::applicationDirPath() +"/j1.frag")){ }
    if(!shaderprogram_tool.link()){ }

    VAO.create();
    VAO.bind();

    VBO_Base.create();
    VBO_Base.bind();

    VBO_Tool.create();
    VBO_Tool.bind();

    shaderprogram_base.setAttributeBuffer("aPos", GL_FLOAT, 0, 3, sizeof(GLfloat) * 6);
    shaderprogram_base.enableAttributeArray("aPos");
    shaderprogram_base.setAttributeBuffer("aNormal", GL_FLOAT,sizeof(GLfloat) * 3, 3, sizeof(GLfloat) * 6);
    shaderprogram_base.enableAttributeArray("aNormal");

    shaderprogram_tool.setAttributeBuffer("aPos", GL_FLOAT, 0, 3, sizeof(GLfloat) * 6);
    shaderprogram_tool.enableAttributeArray("aPos");
    shaderprogram_tool.setAttributeBuffer("aNormal", GL_FLOAT,sizeof(GLfloat) * 3, 3, sizeof(GLfloat) * 6);
    shaderprogram_tool.enableAttributeArray("aNormal");

    this->glEnable(GL_DEPTH_TEST);

    view.setToIdentity();
    view.translate(0,-0.025,0);
    view.lookAt(QVector3D(0.0f, 0.0f, 0.0f), QVector3D(0.0f,0.0f,0.0f), QVector3D(0.0f,0.0f,0.0f));
}

void RSFSWPinToolOpenGLView::resizeGL(int w,int h){
    this->glViewport(0,0,w,h);
    projection.setToIdentity();
    projection.perspective(60.0f, (GLfloat)w/(GLfloat)h, 0.001f, 100.0f);
}

void RSFSWPinToolOpenGLView::paintGL(){
    this->glClearColor(1.0f, 1.0f, 1.0f, 0.8f);//设置清屏颜色
    this->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//清空颜色缓冲区


    shaderprogram_base.bind();
    model.setToIdentity();
    model.translate(xtrans, ytrans, ztrans);
    model.rotate(rotation);
    QVector3D lightColor(1.0f,1.0f,1.0f);
    QVector3D objectColor_base(1.0f,0.5f,0.31f);
    QVector3D lightPos(0.0f,0.0f,50.0f);
    shaderprogram_base.setUniformValue("objectColor",objectColor_base);
    shaderprogram_base.setUniformValue("lightColor",lightColor);
    shaderprogram_base.setUniformValue("lightPos", lightPos);
    shaderprogram_base.setUniformValue("view", view);
    shaderprogram_base.setUniformValue("projection", projection);
    shaderprogram_base.setUniformValue("model", model);
    VBO_Base.allocate(vertices_Base.data(),sizeof(float)*vertices_Base.size());
    this->glDrawArrays(GL_TRIANGLES,0,vertices_Base.capacity()/sizeof(float));


    shaderprogram_tool.bind();
    model.translate(0, 0, 0.003-(0.001*(this->PinPos)));
    model.rotate(0,0,0,1);
    QVector3D objectColor_tool(0.8f,0.8f,0.8f);
    shaderprogram_tool.setUniformValue("objectColor",objectColor_tool);
    shaderprogram_tool.setUniformValue("lightColor",lightColor);
    shaderprogram_tool.setUniformValue("lightPos", lightPos);
    shaderprogram_tool.setUniformValue("view", view);
    shaderprogram_tool.setUniformValue("projection", projection);
    shaderprogram_tool.setUniformValue("model", model);
    VBO_Tool.allocate(vertices_Tool.data(),sizeof(float)*vertices_Tool.size());
    this->glDrawArrays(GL_TRIANGLES,0,vertices_Tool.capacity()/sizeof(float));
}

void RSFSWPinToolOpenGLView::mousePressEvent(QMouseEvent *event){
    mousePos = QVector2D(event->pos());
    event->accept();
}

void RSFSWPinToolOpenGLView::mouseMoveEvent(QMouseEvent *event){
    if(event->buttons() == Qt::LeftButton){
        QVector2D newPos = (QVector2D)event->pos();
        QVector2D diff = newPos - mousePos;
        qreal angle = (diff.length())/3.6;
        QVector3D rotationAxis = QVector3D(diff.y(), diff.x(), 0.0).normalized();
        rotation = QQuaternion::fromAxisAndAngle(rotationAxis, angle) * rotation;
        mousePos = newPos;
        this->update();
    }
    event->accept();
}

void RSFSWPinToolOpenGLView::wheelEvent(QWheelEvent *event){
    QPoint numDegrees = event->angleDelta() / 8;
    if (numDegrees.y() > 0) {
        ztrans += 0.05f;
    } else if (numDegrees.y() < 0) {
        ztrans -= 0.05f;
    }
    this->update();
    event->accept();
}


void RSFSWPinToolOpenGLView::RSFWTooLPinViewUpdate(){
    this->update();
}

void RSFSWPinToolOpenGLView::RSFWTooLPinViewUpdate(double Pos){
    if(this->loaddone == true){
        if(this->looprundelay >= 25){
            this->PinPos = Pos;
            this->update();
        }
        else{
            this->looprundelay = this->looprundelay + 1;
        }
    }
}
